In [1]:
from __future__ import division, print_function, unicode_literals

%matplotlib inline

import os

import IPython.display
import numpy as np

import requests
import requests_oauthlib
import oauthlib
import arrow

import json_io
import yaml_io
import utilities

In [2]:
# Load application's Twitter API details.
fname_twitter_api = 'twitter_api.yml'
info_twitter = yaml_io.read(fname_twitter_api)

client_id = info_twitter['consumer_key']
client_secret = info_twitter['consumer_secret']
access_token = info_twitter['access_token']

# Twitter API urls.
# url_api = 'https://api.twitter.com'
# url_request_oauth1_token = url_api + '/oauth/request_token'
# url_request_oauth2_token = url_api + '/oauth2/token'
# url_authorize = url_api + '/oauth/authorize'
# url_access_token = url_api + '/oauth/access_token'
            
# Backend client.
client = oauthlib.oauth2.BackendApplicationClient(client_id)

# Generate a requests.Session object authorized via OAuth-2.
token = {'access_token': access_token, 'token_type': 'Bearer'}
twitter = requests_oauthlib.OAuth2Session(client, token=token)

In [3]:
# Setup.
url_status = 'https://api.twitter.com/1.1/application/rate_limit_status.json'
params = {'resources': 'search'}

# Request information from Twitter.
response = twitter.get(url_status, params=params)

# Interpret the results.
info_status = response.json()
info_search = info_status['resources']['search']['/search/tweets']

delta = arrow.get(info_search['reset']) - arrow.now()
minutes = delta.total_seconds()/60.

limit = info_search['limit']

remaining = info_search['remaining']

# Display.
print('Rate Limit Status')
print('Limit:  {:d}'.format(limit))
print('Remain: {:d}'.format(remaining))
print('Reset:   {:.1f} min'.format(minutes))


Rate Limit Status
Limit:  450
Remain: 450
Reset:   15.0 min

Twitter Search

The following set of links to Twitter's documentation are those I found most useful:

The page Help with the Search API has this helpful tidbit of information when you expect a large number of return tweets. In this case it is important to pay attention to iterating through the results:

Iterating in a result set: parameters such count, until, since_id, max_id allow to control how we iterate through search results, since it could be a large set of tweets. The 'Working with Timelines' documentation is a very rich and illustrative tutorial to learn how to use these parameters to achieve the best efficiency and reliability when processing result sets.


In [4]:
# Setup.
query = 'grey hound dog'
count = 25

url_search = 'https://api.twitter.com/1.1/search/tweets.json'
params = {'q': query, 'include_entities': True, 'count': count}

# Request information from Twitter.
response = twitter.get(url_search, params=params)

# Interpret the results.
info_search = response.json()

search_meta = info_search['search_metadata']
search_tweets = info_search['statuses']
                            
print('\nSearch metadata')
print('---------------')
IPython.display.display(search_meta)

print('\n\nFirst returned tweet')
print('--------------------')
IPython.display.display(search_tweets[0])


Search metadata
---------------
{u'completed_in': 0.065,
 u'count': 25,
 u'max_id': 417437066792685568,
 u'max_id_str': u'417437066792685568',
 u'query': u'grey+hound+dog',
 u'refresh_url': u'?since_id=417437066792685568&q=grey%20hound%20dog&include_entities=1',
 u'since_id': 0,
 u'since_id_str': u'0'}

First returned tweet
--------------------
{u'contributors': None,
 u'coordinates': None,
 u'created_at': u'Sun Dec 29 23:28:47 +0000 2013',
 u'entities': {u'hashtags': [],
  u'symbols': [],
  u'urls': [],
  u'user_mentions': [{u'id': 172202455,
    u'id_str': u'172202455',
    u'indices': [3, 13],
    u'name': u'angel',
    u'screen_name': u'iSpankHim'}]},
 u'favorite_count': 0,
 u'favorited': False,
 u'geo': None,
 u'id': 417437066792685568,
 u'id_str': u'417437066792685568',
 u'in_reply_to_screen_name': None,
 u'in_reply_to_status_id': None,
 u'in_reply_to_status_id_str': None,
 u'in_reply_to_user_id': None,
 u'in_reply_to_user_id_str': None,
 u'lang': u'en',
 u'metadata': {u'iso_language_code': u'en', u'result_type': u'recent'},
 u'place': None,
 u'retweet_count': 1,
 u'retweeted': False,
 u'retweeted_status': {u'contributors': None,
  u'coordinates': None,
  u'created_at': u'Sun Dec 29 22:39:59 +0000 2013',
  u'entities': {u'hashtags': [],
   u'symbols': [],
   u'urls': [],
   u'user_mentions': []},
  u'favorite_count': 0,
  u'favorited': False,
  u'geo': None,
  u'id': 417424789511213056,
  u'id_str': u'417424789511213056',
  u'in_reply_to_screen_name': None,
  u'in_reply_to_status_id': None,
  u'in_reply_to_status_id_str': None,
  u'in_reply_to_user_id': None,
  u'in_reply_to_user_id_str': None,
  u'lang': u'en',
  u'metadata': {u'iso_language_code': u'en', u'result_type': u'recent'},
  u'place': None,
  u'retweet_count': 1,
  u'retweeted': False,
  u'source': u'<a href="http://twitter.com/download/iphone" rel="nofollow">Twitter for iPhone</a>',
  u'text': u'Alex would be an Italian grey hound if he was a dog',
  u'truncated': False,
  u'user': {u'contributors_enabled': False,
   u'created_at': u'Thu Jul 29 03:55:02 +0000 2010',
   u'default_profile': False,
   u'default_profile_image': False,
   u'description': u"@ispankher's master",
   u'entities': {u'description': {u'urls': []}},
   u'favourites_count': 2776,
   u'follow_request_sent': None,
   u'followers_count': 383,
   u'following': None,
   u'friends_count': 326,
   u'geo_enabled': True,
   u'id': 172202455,
   u'id_str': u'172202455',
   u'is_translator': False,
   u'lang': u'en',
   u'listed_count': 0,
   u'location': u'Wait, so like..',
   u'name': u'angel',
   u'notifications': None,
   u'profile_background_color': u'EBEBEB',
   u'profile_background_image_url': u'http://a0.twimg.com/profile_background_images/378800000076784743/f5e0b38bb54d9eeb565d9f0e759b3946.jpeg',
   u'profile_background_image_url_https': u'https://si0.twimg.com/profile_background_images/378800000076784743/f5e0b38bb54d9eeb565d9f0e759b3946.jpeg',
   u'profile_background_tile': True,
   u'profile_banner_url': u'https://pbs.twimg.com/profile_banners/172202455/1388136317',
   u'profile_image_url': u'http://pbs.twimg.com/profile_images/416883944898850816/uUUTLpUb_normal.jpeg',
   u'profile_image_url_https': u'https://pbs.twimg.com/profile_images/416883944898850816/uUUTLpUb_normal.jpeg',
   u'profile_link_color': u'990000',
   u'profile_sidebar_border_color': u'FFFFFF',
   u'profile_sidebar_fill_color': u'F3F3F3',
   u'profile_text_color': u'333333',
   u'profile_use_background_image': True,
   u'protected': False,
   u'screen_name': u'iSpankHim',
   u'statuses_count': 13752,
   u'time_zone': u'Pacific Time (US & Canada)',
   u'url': None,
   u'utc_offset': -28800,
   u'verified': False}},
 u'source': u'<a href="https://twitter.com/download/android" rel="nofollow">Twitter for  Android</a>',
 u'text': u'RT @iSpankHim: Alex would be an Italian grey hound if he was a dog',
 u'truncated': False,
 u'user': {u'contributors_enabled': False,
  u'created_at': u'Fri Jun 01 02:06:04 +0000 2012',
  u'default_profile': False,
  u'default_profile_image': False,
  u'description': u'@ispankhim is a rapist',
  u'entities': {u'description': {u'urls': []}},
  u'favourites_count': 3926,
  u'follow_request_sent': None,
  u'followers_count': 599,
  u'following': None,
  u'friends_count': 336,
  u'geo_enabled': True,
  u'id': 596024162,
  u'id_str': u'596024162',
  u'is_translator': False,
  u'lang': u'en',
  u'listed_count': 0,
  u'location': u'Trap  rap and rock music',
  u'name': u'Jaguar Paw',
  u'notifications': None,
  u'profile_background_color': u'022330',
  u'profile_background_image_url': u'http://a0.twimg.com/profile_background_images/378800000078893736/5de1872bb71b06e22a3584260f1af4a0.jpeg',
  u'profile_background_image_url_https': u'https://si0.twimg.com/profile_background_images/378800000078893736/5de1872bb71b06e22a3584260f1af4a0.jpeg',
  u'profile_background_tile': True,
  u'profile_banner_url': u'https://pbs.twimg.com/profile_banners/596024162/1388346211',
  u'profile_image_url': u'http://pbs.twimg.com/profile_images/411906249874100224/h8DcLVj5_normal.jpeg',
  u'profile_image_url_https': u'https://pbs.twimg.com/profile_images/411906249874100224/h8DcLVj5_normal.jpeg',
  u'profile_link_color': u'0084B4',
  u'profile_sidebar_border_color': u'FFFFFF',
  u'profile_sidebar_fill_color': u'C0DFEC',
  u'profile_text_color': u'333333',
  u'profile_use_background_image': True,
  u'protected': False,
  u'screen_name': u'ISpankHer',
  u'statuses_count': 11243,
  u'time_zone': u'Pacific Time (US & Canada)',
  u'url': None,
  u'utc_offset': -28800,
  u'verified': False}}

Rate limit information is also contained within response header.


In [18]:
for k in ['x-rate-limit-remaining', 'x-rate-limit-limit', 'x-rate-limit-reset']:
    v = response.headers[k]
    print(k, v)


x-rate-limit-remaining 449
x-rate-limit-limit 450
x-rate-limit-reset 1388426947

In [ ]: